<script setup lang="ts" name="GoodsSku">
import { GoodsInfo, Spec, SpecValue } from '@/types/goods'
import bwPowerSet from '@/utils/power-set'
// goods-sku组件 - 基本使用
// 1. 传入商品信息 - 启用禁用, 选择功能
// 2. 传入skuId (可选) - 默认回显, 将一些规格选中
// 3. 选中全部规格之后, 确定sku, 利用子传父, 将sku传给父组件 - 控制商品的显示价格...
const props = defineProps<{
  goods: GoodsInfo
  skuId?: string
}>()

const emit = defineEmits<{
  (e: 'changeSku', skuId: string): void
}>()

// 2. 获取路径字典
const getPathMap = () => {
  const pathMap: {
    [key: string]: string[]
  } = {}
  // 1. 过滤掉库存 inventory为0的sku
  const skus = props.goods.skus.filter(item => item.inventory > 0)
  // console.log('--有效的skus-', skus);  // 4个 
  // 2. 遍历有效的sku组合. 获取幂集/ 子集集合
  skus.forEach(item => {
    const arr = item.specs.map(sub => sub.valueName)
    // console.log('arr', arr);
    // 调用bwPowerSet - 子集集合
    // console.log(bwPowerSet(arr));
    // 3. 把bwPowerSet的子集集合的数据合并到一个路径字典中
    const powerSet = bwPowerSet(arr)
    powerSet.forEach(sub => {
      const key = sub.join('+')
      // console.log(key);
      // 4. 判断pathMap中有没有key
      // {
      //   a: [100, 200, 新添加的id],
      // }
      // a in 对象 存在  将sku的id 添加到  push(item.id)
      // c in 对象 不存在 obj[key] = [id]
      if (key in pathMap) {
        // 该属性存在于对象中
        pathMap[key].push(item.id)
      } else {
        // 该属性不存在于对象中
        pathMap[key] = [item.id]
      }
    })
  })
  return pathMap
}

// 4. 获取选中的规格
const getSelectdSpec = () => {
  const arr: string[] = []
  // 需要遍历规格 specs - 找选中(selected)的规格属性 
  // console.log(props.goods.specs);
  props.goods.specs.forEach(item => {
    const temp = item.values.find(sub => sub.selected)
    // console.log(temp);
    arr.push(temp ? temp.name : '')
  })
  return arr
}

// 3. 处理 - 默认禁用的按钮
// 思路: 遍历所有的规格按钮, 判断是否出现在路径字典中 pathMap, 如果没有出现, 需要禁用
const pathMap = getPathMap() // pathMap 路径字典
// console.log(pathMap);

// 封装函数 - 更新按钮的禁用状态
const updateDisabledStatus = () => {
  // 获取选中的规格
  const selectArr = getSelectdSpec() // ['', '', '']
  // console.log('获取选中的规格', selectArr);
  props.goods.specs.forEach((item, index) => {
    item.values.forEach(sub => {
      // 让当前这个按钮, sub.name (蓝色) 和 selectArr 进行组合  ['蓝色', '', '']
      // 注意点: 为了尝试进行组合, 判断是否禁用 需要拷贝一份原数组
      const tempArr = [...selectArr]
      tempArr[index] = sub.name  // ['', '蓝色', '']
      // 得到组合后的数组, 转成key  ['黑色', '', '30cm']
      // 注意点: 需要把 '' 从数组中过滤出去  ['黑色', '30cm'] - '黑色+30cm'
      const key = tempArr.filter(item => item).join('+')
      // 判断组合过后的字符串 - 是否在路径字典中
      if (key in pathMap) {
        // 当前的规格的名字出现在pathMap中, 不禁用 (有库存)
        sub.disabled = false
      } else {
        // 当前的规格的名字没有出现在pathMap中, 禁用 (没有库存)
        // console.log(sub.name);
        sub.disabled = true
      }
    })
  })
}

// 5. 初始化默认选中状态

const initSelectedSpec = () => {
  const sku = props.goods.skus.find(item => item.id === props.skuId)
  // console.log(sku);
  if (sku) {
    // 根据父组件传递过来的skuid 找到对应的sku - 设置默认选中
    props.goods.specs.forEach((item, index) => {
      // 获取到sku选中的规格 - 蓝色 中国 10cm
      const value = sku.specs[index].valueName
      // console.log(value);
      // 让value的对应的规格选中
      const spec = item.values.find(item => item.name === value)
      spec!.selected = true
    })

  }
}
// 注意点: 先设置默认选中, 再设置默认禁用
initSelectedSpec()
// 初始化, 控制规格按钮的选中状态
updateDisabledStatus()

// 1. 处理规格属性选中的状态
const changeSelected = (item: Spec, sub: SpecValue) => {
  // 禁用的按钮, 不应该能被选中
  if (sub.disabled) return

  // 判断 属性是否选中
  if (sub.selected) {
    // 如果是选中了, 取消选中
    sub.selected = false
  } else {
    // 把同级/一行的sub全部取消选中
    item.values.forEach(v => v.selected = false)
    // 如果未选中, 让sub 选中
    sub.selected = true
  }
  // 每一次点击, 需要更新按钮的禁用状态
  updateDisabledStatus()
  // 判断规格是否全部选中
  const isSelected = getSelectdSpec().filter(item => item)
  if (isSelected.length === props.goods.specs.length) {
    // 全部选中
    const key = isSelected.join('+')  // '黑色+日本+30cm'
    // 通过解构获取skuId 
    const [skuId] = pathMap[key]
    // 子传父 
    emit('changeSku', skuId) // SkuId 完整的sku
  } else {
    // 未全部选中
    emit('changeSku', '')
  }
}

</script>
<template>
  <div class="goods-sku">
    <!-- specs 商品的规格 -->
    <dl v-for="item in goods.specs">
      <dt>{{ item.name }}</dt>
      <!-- selected  disabled-->
      <dd>
        <template v-for="sub in item.values" :key="sub.name">
          <img @click="changeSelected(item, sub)" :class="{ selected: sub.selected, disabled: sub.disabled }"
            v-if="sub.picture" :src="sub.picture" alt="" />
          <span @click="changeSelected(item, sub)" :class="{ selected: sub.selected, disabled: sub.disabled }" v-else>{{
              sub.name
          }}</span>
        </template>

      </dd>
    </dl>
  </div>
</template>

<style scoped lang="less">
.sku-state-mixin () {
  border: 1px solid #e4e4e4;
  margin-right: 10px;
  cursor: pointer;

  // 规格属性选中的类名
  &.selected {
    border-color: @xtxColor;
  }

  // 规格属性禁用的类名
  &.disabled {
    opacity: 0.6;
    border-style: dashed;
    cursor: not-allowed;
  }
}

.goods-sku {
  padding-left: 10px;
  padding-top: 20px;

  dl {
    display: flex;
    padding-bottom: 20px;
    align-items: center;

    dt {
      width: 50px;
      color: #999;
    }

    dd {
      flex: 1;
      color: #666;

      >img {
        width: 50px;
        height: 50px;
        margin-top: 5px;
        .sku-state-mixin ();
      }

      >span {
        display: inline-block;
        height: 30px;
        line-height: 30px;
        padding: 0 20px;
        margin-top: 5px;
        .sku-state-mixin ();
      }
    }
  }
}
</style>

